﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Meebey.SmartIrc4net;
using System.Configuration;
using System.Net;
using System.IO;
using System.Xml;
using System.Xml.XPath;

namespace WinBolo_Tracker
{
    public partial class frmSettings : Form
    {
        delegate void StartDelegate(Bot bot, Game game, Map map);
        delegate void KillDelegate(Bot bot, Game game);
        delegate void LockDelegate(Bot bot, Game game);
        
        List<Game> gameList = new List<Game>();
        List<Bot> botList = new List<Bot>();
        List<Map> mapList = new List<Map>();

        Process p = null;

        // List of port numbers of IRC hosted games started by the user
        List<int> portList = new List<int>();
        
        public static IrcClient irc = new IrcClient();
        Ini.IniFile iniFile = new Ini.IniFile(Application.UserAppDataPath + @"\tracker.ini");

        string winboloRSSFeed = "";

        public frmSettings()
        {
            InitializeComponent();

            InitConfig();

            ApplyConfiguration();

            TrackAndRefresh();

            CleanUp();

            timer.Enabled = true;

        }

        private bool NotActive(int port)
        {
            bool remove = true;
            foreach (Game game in gameList)
            {
                remove = remove && (game.Port != port);
            }
            return remove;
        }

        private void CleanUp()
        {
            portList.RemoveAll(NotActive);
        }

        private void InitConfig()
        {
            XPathNavigator nav;
            XPathDocument docNav;

            Stream s = GetConfigFile();

            if (s == null)
            {
                grpIRCBot.Enabled = false;
                return;
            }

            docNav = new XPathDocument(s);
            nav = docNav.CreateNavigator();

            XPathNodeIterator bots = nav.Select("config/bots/bot");
            foreach (XPathNavigator bot in bots)
            {
                Bot botItem = new Bot();
                bool resultBool;

                botItem.Server = bot.GetAttribute("server", String.Empty);
                botItem.Host = bot.GetAttribute("host", String.Empty);
                botItem.Channel = bot.GetAttribute("channel", String.Empty);
                botItem.Port = bot.GetAttribute("port", String.Empty);
                botItem.Name = bot.GetAttribute("name", String.Empty);
                botItem.SuccResponse = bot.GetAttribute("succresponse", String.Empty);
                botItem.ErrResponse = bot.GetAttribute("errresponse", String.Empty);
                botItem.CmdMapStrict = bot.GetAttribute("cmdmapstrict", String.Empty);
                botItem.CmdMapOpen = bot.GetAttribute("cmdmapopen", String.Empty);
                if (bool.TryParse(bot.GetAttribute("cankill", String.Empty), out resultBool))
                    botItem.CanKill = resultBool;
                else
                    botItem.CanKill = false;
                if (bool.TryParse(bot.GetAttribute("canlock", String.Empty), out resultBool))
                    botItem.CanLock = resultBool;
                else
                    botItem.CanLock = false;

                botList.Add(botItem);
            }

            XPathNodeIterator maps = nav.Select("config/maps/map");
            foreach (XPathNavigator map in maps)
            {
                Map mapItem = new Map();

                mapItem.Name = map.GetAttribute("name", String.Empty);

                mapList.Add(mapItem);
            }

        }

        private Stream GetConfigFile()
        {
            // used to build entire input
            StringBuilder sb = new StringBuilder();

            // used on each read operation
            byte[] buf = new byte[8192];

            // prepare the web page we will be asking for
            HttpWebRequest request = (HttpWebRequest)
                WebRequest.Create("http://swenug.com/tracker/config.xml");

            try
            {
                // execute the request
                HttpWebResponse response = (HttpWebResponse)
                    request.GetResponse();

                // we will read data via the response stream
                Stream resStream = response.GetResponseStream();

                return resStream;
            }
            catch (Exception e)
            {
                Logger.Log(e.Message);

                return null;
            }
            
        }

        private void ApplyConfiguration()
        {
            bool resultBool;
            int resultInt;

            // Populate bot list
            foreach (Bot bot in botList)
                cmbBotList.Items.Add(bot);
            if (cmbBotList.Items.Count > 0)
                cmbBotList.SelectedIndex = 0;

            // Populate map list
            foreach (Map map in mapList)
                cmbMapList.Items.Add(map);
            if (cmbMapList.Items.Count > 0)
                cmbMapList.SelectedIndex = 0;
            
            if (bool.TryParse(iniFile.IniReadValue("Settings", "AutoRefresh"), out resultBool))
                chkAutoRefresh.Checked = resultBool;
            else
                chkAutoRefresh.Checked = false;

            txtLocalMap.Text = iniFile.IniReadValue("Settings", "LocalMap");
            txtLocalServer.Text = iniFile.IniReadValue("Settings", "LocalServer");
            txtLocalPort.Text = iniFile.IniReadValue("Settings", "LocalPort");

            txtIRCServer.Text = iniFile.IniReadValue("Settings", "IRCServer");
            txtIRCChannel.Text = iniFile.IniReadValue("Settings", "IRCChannel");
            txtIRCPort.Text = iniFile.IniReadValue("Settings", "IRCPort");
            txtIRCBotName.Text = iniFile.IniReadValue("Settings", "IRCBotName");

            txtIRCMap.Text = iniFile.IniReadValue("Settings", "IRCMap");
            if (txtIRCMap.Text == "")
                txtIRCMap.Text = "Chew Toy 3.map";

            if (bool.TryParse(iniFile.IniReadValue("Settings", "AutoStartHostedGame"), out resultBool))
                chkAutostartHostedGame.Checked = resultBool;
            else
                chkAutostartHostedGame.Checked = false;

            txtTracker.Text = iniFile.IniReadValue("Settings", "Tracker");
            if (txtTracker.Text == "")
                txtTracker.Text = "tracker.winbolo.net";
            
            txtTrackerPort.Text = iniFile.IniReadValue("Settings", "TrackerPort");
            if (txtTrackerPort.Text == "")
                txtTrackerPort.Text = "50000";

            txtPollTime.Text = iniFile.IniReadValue("Settings", "TrackerPollTime");
            if (txtPollTime.Text == "")
                txtPollTime.Text = "5000";

            if (bool.TryParse(iniFile.IniReadValue("Settings", "PlaySoundNewGame"), out resultBool))
                chkPlaySoundNewGame.Checked = resultBool;
            else
                chkPlaySoundNewGame.Checked = true;

            if (bool.TryParse(iniFile.IniReadValue("Settings", "PlaySoundStartGame"), out resultBool))
                chkPlaySoundStartGame.Checked = resultBool;
            else
                chkPlaySoundStartGame.Checked = true;

            if (int.TryParse(iniFile.IniReadValue("Settings", "TrackerPollTime"), out resultInt))
                timer.Interval = resultInt;
            else
                timer.Interval = 5000;

            winboloRSSFeed = iniFile.IniReadValue("Settings", "WinboloRSSFeed");
            if (winboloRSSFeed == "")
                winboloRSSFeed = "http://www.winbolo.net/rss/current_games.xml";

            string portListSetting = iniFile.IniReadValue("Settings", "PortList");
            foreach (string token in portListSetting.Split(new char[] { ';' }))
            {
                if (token != "")
                    portList.Add(int.Parse(token));
            }
        }
        
        #region Events

        #region Tray Icon events

        // User clicked open Settings form from tray icon
        private void toolStripMenuSettings_Click(object sender, EventArgs e)
        {
            // Refresh the list of games
            RefreshGameList();
            
            // Show the form
            ShowWindow();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Save state here
            // TBD

            ExitTracker();
        }

        private void ExitTracker()
        {
            SaveConfiguration();

            Application.Exit();
        }

        private void SaveConfiguration()
        {
            iniFile.IniWriteValue("Settings", "AutoRefresh", chkAutoRefresh.Checked.ToString());
            iniFile.IniWriteValue("Settings", "LocalMap", txtLocalMap.Text);
            iniFile.IniWriteValue("Settings", "LocalServer", txtLocalServer.Text);
            iniFile.IniWriteValue("Settings", "LocalPort", txtLocalPort.Text);
            iniFile.IniWriteValue("Settings", "IRCServer", txtIRCServer.Text);
            iniFile.IniWriteValue("Settings", "IRCChannel", txtIRCChannel.Text);
            iniFile.IniWriteValue("Settings", "IRCPort", txtIRCPort.Text);
            iniFile.IniWriteValue("Settings", "IRCBotName", txtIRCBotName.Text);
            iniFile.IniWriteValue("Settings", "IRCMap", txtIRCMap.Text);
            iniFile.IniWriteValue("Settings", "WinboloRSSFeed", winboloRSSFeed);
            iniFile.IniWriteValue("Settings", "AutoStartHostedGame", chkAutostartHostedGame.Checked.ToString());
            iniFile.IniWriteValue("Settings", "Tracker", txtTracker.Text);
            iniFile.IniWriteValue("Settings", "TrackerPort", txtTrackerPort.Text);
            iniFile.IniWriteValue("Settings", "TrackerPollTime", txtPollTime.Text);
            iniFile.IniWriteValue("Settings", "PlaySoundNewGame", chkPlaySoundNewGame.Checked.ToString());
            iniFile.IniWriteValue("Settings", "PlaySoundStartGame", chkPlaySoundStartGame.Checked.ToString());
            string portListSetting = "";
            foreach (int port in portList)
                portListSetting += port.ToString() + ";";
            iniFile.IniWriteValue("Settings", "PortList", portListSetting);
        }

        private void notifyIconTank_BalloonTipClicked(object sender, EventArgs e)
        {
            this.tabControl.TabPages[0].Select();

            RefreshGameList();

            ShowWindow();
        }

        private void notifyIconTank_DoubleClick(object sender, EventArgs e)
        {
            ShowWindow();
        }

        #endregion

        private void btnHide_Click(object sender, EventArgs e)
        {
            HideWindow();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            timer.Enabled = false;

            lock (this.gameList)
            {
                Track(true);

                RefreshGameList();
                
            }

            timer.Enabled = true;
        }



        private void btnStartGame_Click(object sender, EventArgs e)
        {
            StartGame(gameList[lstGameList.SelectedIndex]);
        }

        private void frmSettings_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!(e.CloseReason == CloseReason.ApplicationExitCall))
            {
                HideWindow();
                e.Cancel = true;
            }
        }

        private void chkAutoStart_CheckedChanged(object sender, EventArgs e)
        {
            gameList[this.lstGameList.SelectedIndex].AutoStart = chkAutoStart.Checked;
        }

        private void chkAutoRefresh_CheckedChanged(object sender, EventArgs e)
        {
            timer.Enabled = chkAutoRefresh.Checked;
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            StartServer();

            MessageBox.Show("Don't forget to open up any firewall or forward the port for port number " + txtLocalPort.Text, "Connection", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void btnRefreshGameList_Click(object sender, EventArgs e)
        {
            TrackAndRefresh();
        }

        #region Game preferences tab events

        private void radTrackAllGames_CheckedChanged(object sender, EventArgs e)
        {
            SetSubscribersControl(!radTrackAllGames.Checked);
        }

        private void SetSubscribersControl(bool value)
        {
            chkOpen.Enabled = value;
            chkLocked.Enabled = value;
            chkProtected.Enabled = value;
            chkUnlocked.Enabled = value;
            chkUnprotected.Enabled = value;
            chkStrict.Enabled = value;
            chkAllVersions.Enabled = value;
            txtVersion.Enabled = value;
        }

        #endregion

        #region Active games tab events

        #region Game list events

        private void lstGameList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.lstGameList.SelectedIndex >= gameList.Count)
                return;

            lblMap.Text = gameList[this.lstGameList.SelectedIndex].Map;
            lblPort.Text = gameList[this.lstGameList.SelectedIndex].Port.ToString();
            lblType.Text = gameList[this.lstGameList.SelectedIndex].Type;
            lblVersion.Text = gameList[this.lstGameList.SelectedIndex].Version;
            lblPlayers.Text = gameList[this.lstGameList.SelectedIndex].Players.ToString();
            lblPills.Text = gameList[this.lstGameList.SelectedIndex].Pills.ToString();
            lblBases.Text = gameList[this.lstGameList.SelectedIndex].Bases.ToString();
            chkAutoStart.Checked = gameList[this.lstGameList.SelectedIndex].AutoStart;
            chkAutoStart.Enabled = gameList[this.lstGameList.SelectedIndex].Players == 0 && !gameList[this.lstGameList.SelectedIndex].Killed;
            lblLocked.Text = gameList[this.lstGameList.SelectedIndex].Locked ? "Yes" : "No";
            btnPlay.Enabled = !gameList[this.lstGameList.SelectedIndex].Killed;

            lstPlayers.Items.Clear();
            if (gameList[this.lstGameList.SelectedIndex].PlayerList.Count > 0)
            {
                foreach (Player player in gameList[this.lstGameList.SelectedIndex].PlayerList)
                    lstPlayers.Items.Add(player.Name);
            }
            else
                lstPlayers.Items.Add("No players identified");
        }

        private void lstGameList_DrawItem(object sender, DrawItemEventArgs e)
        {
            e.DrawBackground();

            if (e.Index == -1) return;

            Game game = (Game)((ListBox)sender).Items[e.Index];
            Brush myBrush = Brushes.Black;
            Font tagFont = new Font(FontFamily.GenericSansSerif, (float)8.25, FontStyle.Bold);
            Font defaultFont = new Font(FontFamily.GenericSansSerif, (float)8.25, FontStyle.Regular);

            if (game == null) return;

            //if (game.IsNew)
            //    myBrush = Brushes.Blue; // New games
            if (game.Killed)
                myBrush = Brushes.Red; // Killed games
            else if (portList.Contains(game.Port))
                myBrush = Brushes.Green; // Your hosted games
            else
                myBrush = Brushes.Black;

            if (game.Players > 0)
                e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
                    tagFont, myBrush, e.Bounds, StringFormat.GenericDefault);
            else
                e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
                    defaultFont, myBrush, e.Bounds, StringFormat.GenericDefault);

            e.DrawFocusRectangle();

        }

        private void lstGameList_DoubleClick(object sender, EventArgs e)
        {

            StartGame(gameList[this.lstGameList.SelectedIndex]);
        }

        
        private void killToolStripMenuItem_Click(object sender, EventArgs e)
        {
            KillDelegate killDelegate = new KillDelegate(KillIRCGame);

            Bot bot = botList.Find(b => b.Host == gameList[this.lstGameList.SelectedIndex].Address);

            killDelegate.BeginInvoke(bot, gameList[this.lstGameList.SelectedIndex], new AsyncCallback(this.KillIRCGameCallback), killDelegate);

            gameList[this.lstGameList.SelectedIndex].Killed = true;

        }

        private void KillIRCGameCallback(IAsyncResult ar)
        {
            KillDelegate d = (KillDelegate)ar.AsyncState;
            //this.BeginInvoke(
            //     (MethodInvoker)delegate()
            //     {
            //         this.btnStartIRCGame.Enabled = true;
            //     });
        }


        private void lockedToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LockDelegate lockDelegate = new LockDelegate(LockIRCGame);
            LockDelegate unlockDelegate = new LockDelegate(UnlockIRCGame);

            if (lockedToolStripMenuItem.Checked)
                unlockDelegate.BeginInvoke((Bot)cmbBotList.SelectedItem, gameList[this.lstGameList.SelectedIndex], new AsyncCallback(this.LockIRCGameCallback), unlockDelegate);
            else
                lockDelegate.BeginInvoke((Bot)cmbBotList.SelectedItem, gameList[this.lstGameList.SelectedIndex], new AsyncCallback(this.LockIRCGameCallback), lockDelegate);

            lockedToolStripMenuItem.Checked = !lockedToolStripMenuItem.Checked;

            gameList[this.lstGameList.SelectedIndex].ForceLocked = lockedToolStripMenuItem.Checked;

        }

        private void LockIRCGameCallback(IAsyncResult ar)
        {
            LockDelegate d = (LockDelegate)ar.AsyncState;
            //this.BeginInvoke(
            //     (MethodInvoker)delegate()
            //     {
            //         this.btnStartIRCGame.Enabled = true;
            //     });
        }

        private void copyToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(string.Format("{0}:{1}",
                gameList[lstGameList.SelectedIndex].Address,
                gameList[lstGameList.SelectedIndex].Port));

        }

        private void playToolStripMenuItem_Click(object sender, EventArgs e)
        {
            StartGame(gameList[this.lstGameList.SelectedIndex]);
        }

        private void lstGameList_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                Point p = new Point(e.X, e.Y);
                lstGameList.SelectedIndex = lstGameList.IndexFromPoint(p);

                contextGameList.Items["killToolStripMenuItem"].Enabled = false;
                contextGameList.Items["lockedToolStripMenuItem"].Enabled = false;
                // if IRC hosted game and not already killed
                if (!gameList[this.lstGameList.SelectedIndex].Killed)
                {
                    // if game started by the user and no players in the game
                    if (portList.Contains(gameList[this.lstGameList.SelectedIndex].Port))
                    {
                        if (gameList[this.lstGameList.SelectedIndex].Players == 0)
                            contextGameList.Items["killToolStripMenuItem"].Enabled = botList.Find(b => b.Host == gameList[this.lstGameList.SelectedIndex].Address).CanKill;
                        contextGameList.Items["lockedToolStripMenuItem"].Enabled = botList.Find(b => b.Host == gameList[this.lstGameList.SelectedIndex].Address).CanLock;
                    }
                }
                lockedToolStripMenuItem.Checked = gameList[this.lstGameList.SelectedIndex].ForceLocked || gameList[this.lstGameList.SelectedIndex].Locked;
                contextGameList.Items["playToolStripMenuItem"].Enabled = !gameList[this.lstGameList.SelectedIndex].Killed;
                contextGameList.Items["autoStartToolStripMenuItem"].Enabled = gameList[this.lstGameList.SelectedIndex].Players == 0 && !gameList[this.lstGameList.SelectedIndex].Killed;
            }
        }

        #endregion

        #endregion

        #region Hosting tab events

        private void btnStartIRCGame_Click(object sender, EventArgs e)
        {
            StartDelegate d = new StartDelegate(StartIRCGame);

            btnStartIRCGame.Enabled = false;

            if (radCustom.Checked)
            {
                Map map = new Map() { Name = txtIRCMap.Text };
                Bot bot = new Bot() { Server = txtIRCServer.Text, Channel = txtIRCChannel.Text, Port = txtIRCPort.Text, CanKill = chkCanKill.Checked, CanLock = chkCanLock.Checked, Name = txtIRCBotName.Text, CanMapOpen = false, CmdMapOpen = "", CmdMapStrict = "map", SuccResponse = "", ErrResponse = "" };
            }
            else
                d.BeginInvoke((Bot)cmbBotList.SelectedItem, new Game() { Type = radOpen.Checked ? "Open" : "Strict" }, (Map)cmbMapList.SelectedItem, new AsyncCallback(this.StartIRCGameCallback), d);
        }

        private void StartIRCGameCallback(IAsyncResult ar)
        {
            StartDelegate d = (StartDelegate)ar.AsyncState;
            this.BeginInvoke(
                 (MethodInvoker)delegate()
                 {
                     this.btnStartIRCGame.Enabled = true;
                 });
        }

        #endregion

        #endregion

        #region Methods

        private void HideWindow()
        {
            timer.Enabled = true;
            this.Visible = false;
            this.WindowState = FormWindowState.Minimized;

        }

        private void ShowWindow()
        {
            if (!this.chkAutoRefresh.Checked)
                timer.Enabled = false;
            
            this.Visible = true;
            this.WindowState = FormWindowState.Normal;
            this.Refresh();
            this.Focus();
        }

        // Balloon tip for new games, if prompt is true
        private void Track(bool prompt)
        {
            // Parse tracking information
            Tracker tracker = Parser.Parse(Network.SocketSendReceive(txtTracker.Text, int.Parse(txtTrackerPort.Text)));

            if (tracker == null)
            {
                lblStatus.Text = "Network problems";
                Logger.Log((IList<object>)lstLog.Items, "Parser returned null");
                return;
            }

            for (int i = 0; i < tracker.NGames; i++)
            {
                //tracker.Games[i].Filtered = !(chkOpen.Checked && tracker.Games[i].Type == "Open"); // (tracker.Games[i].Type == "Open" && !chkOpen.Checked) || tracker.Games[i].Filtered;
                //tracker.Games[i].Filtered = !(chkStrict.Checked && tracker.Games[i].Type == "Strict") || tracker.Games[i].Filtered;
            }


            int numberOfNewGames = 0;

            // Compare old and new list
            for (int x = 0; x < tracker.NGames; x++)
            {
                
                bool isNewGame = true;
                foreach (Game game in gameList)
                {
                    isNewGame = !game.Compare(tracker.Games[x]);
                    if (!isNewGame)
                    {
                        // Copy old game properties to new list
                        tracker.Games[x].Killed = game.Killed;
                        tracker.Games[x].AutoStart = game.AutoStart;
                        tracker.Games[x].ForceLocked = game.ForceLocked;

                        if (game.AutoStart && game.Players > 0)
                        {
                            StartGame(gameList[this.lstGameList.SelectedIndex]);

                            if (chkPlaySoundStartGame.Checked)
                                Win32.Winmm.PlayWavResource("gamestarted.wav");

                            tracker.Games[x].AutoStart = false;
                        }
                        break;
                    }
                }
                tracker.Games[x].IsNew = isNewGame;
            }

            // Complement with winbolo.net data
            RssFeed feed = RssReader.GetFeed(winboloRSSFeed);

            foreach (RssItem item in feed.Items)
            {
                Game game = Parser.Parse(item.Title, item.Description);

                for (int i = 0; i < tracker.NGames; i++)
                {
                    if (game.Compare2(tracker.Games[i]))
                    {
                        tracker.Games[i].Locked = game.Locked;
                        if (tracker.Games[i].Players > 0)
                        {
                            foreach (Player player in game.PlayerList)
                                tracker.Games[i].PlayerList.Add(player);
                        }
                    }
                }
            }
           
            // Rebuild the game list
            gameList.Clear();
            for (int x = 0; x < tracker.NGames; x++)
            {
                if (tracker.Games[x].IsNew)
                    numberOfNewGames++;
                gameList.Insert(0, tracker.Games[x]);
            }

            
            // Prompt if any new games
            // Subscription based is TBD
            if (numberOfNewGames > 0)
            {
                notifyIconTank.BalloonTipTitle = numberOfNewGames.ToString() + " new game(s) found";
                notifyIconTank.BalloonTipText = "";
                foreach (Game game in gameList)
                {
                    if (game.IsNew && prompt && !game.Filtered)
                        notifyIconTank.BalloonTipText += string.Format("{0} ({1})\n", game.Map, game.Type);
                }
                if (prompt)
                {
                    notifyIconTank.ShowBalloonTip(5000);

                    if (chkPlaySoundNewGame.Checked)
                        Win32.Winmm.PlayWavResource("newgame.wav");
                }
            }

            lblStatus.Text = "OK";
        }

        private void RefreshGameList()
        {
            int hash = 0;

            if (gameList.Count == 0)
                return;

            try
            {

                if (this.lstGameList.SelectedIndex >= 0)
                    hash = gameList[this.lstGameList.SelectedIndex].GetHashCode();

                this.lstGameList.Items.Clear();

                int i = 0;
                foreach (Game game in gameList)
                {
                    if (!game.Filtered)
                    {
                        this.lstGameList.Items.Add(game);
                        if (game.GetHashCode() == hash)
                            this.lstGameList.SelectedIndex = i;
                        i++;
                    }
                }

                if (hash == 0)
                    this.lstGameList.SelectedIndex = 0;
            }
            catch (Exception e)
            {
            }
        }

        private void StartGame(Game game)
        {

            Process.Start(string.Format("winbolo://{0}:{1}/", game.Address, game.Port));
        }

        private void StartServer()
        {
            string command = "";
            command = String.Format(@"-map ""{0}"" -port {1} -gametype {2} -mines {3} -tracker {4}:{5} {6}",
                txtLocalMap.Text, txtLocalPort.Text,
                radLocalStrict.Checked ? "Strict" : "Open",
                chkLocalMines.Checked ? "yes" : "no",
                txtTracker.Text, txtTrackerPort.Text,
                chkLocalQuiet.Checked ? "-quite" : "");

            p = new Process();
            p.StartInfo.FileName = txtLocalServer.Text;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.Arguments = command;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.RedirectStandardInput = true;
            p.Start();
            StreamWriter myStreamWriter = p.StandardInput;

            //Thread.Sleep(10000);
            //myStreamWriter.WriteLine("lock");
            //Thread.Sleep(10000);
            //myStreamWriter.WriteLine("unlock");
            //Thread.Sleep(10000);
            //myStreamWriter.WriteLine("say 10 seconds to quit");
            //Thread.Sleep(10000);
            //myStreamWriter.WriteLine("quit");

//            Process.Start(txtLocalServer.Text, command);
        }

        #endregion


        #region IRC code

        // this method handles when we receive "ERROR" from the IRC server
        static void OnError(object sender, Meebey.SmartIrc4net.ErrorEventArgs e)
        {
            System.Console.WriteLine("Error: " + e.ErrorMessage);
        }
        
        // this method will get all IRC messages
        void OnRawMessage(object sender, IrcEventArgs e)
        {
            Bot bot = ((Bot)((IrcClient)sender).Tag);

            string result = e.Data.RawMessage;

            if (result.Contains(bot.SuccResponse))
            {
                // ":Minbot!~minbot@minhiriath.xen.prgmr.com PRIVMSG #winbolo :winbolo://minhiriath.xen.prgmr.com:30523 - Chew Toy 3.map - Strict"
                int POS1 = result.IndexOf(bot.SuccResponse);
                int port = int.Parse(result.Substring(POS1 + bot.SuccResponse.Length + 1, 5));

                this.BeginInvoke(
                     (MethodInvoker)delegate()
                     {
                         portList.Add(port);
                     });
            }

            string[] errTokens = bot.ErrResponse.Split(new char[] { ':' });

            bool contained = false;
            foreach (string token in errTokens)
                contained = contained || result.Contains(token);
            
            if (result.Contains(bot.SuccResponse) || contained)
            {
                irc.Disconnect();
            }

//            ":bottie!wbb@bottie.winbolo.us PRIVMSG #winbolo :chew toy 3.map @ winbolo://bottie.winbolo.us:27537 - strict for 16 players - password: ugh"

        }

        // <+bottie> ack! ya got me! WP just killed port 27519 on bottie.winbolo.us
        [System.Obsolete("Use StartIRCGame(Bot, Map)")]
        void KillIRCGame(string server, string channel, Game game)
        {
            SendIRCCommand(server, channel, "Minbot kill " + game.Port.ToString());
        }

        void KillIRCGame(Bot bot, Game game)
        {
            SendIRCCommand(bot.Server, bot.Port, bot.Channel, 
                string.Format("{0} {1} {2}", bot.Name, "kill", game.Port.ToString()), bot);
        }

        void LockIRCGame(Bot bot, Game game)
        {
            SendIRCCommand(bot.Server, bot.Port, bot.Channel,
                string.Format("{0} {1} {2}", bot.Name, "lock", game.Port.ToString()), bot);
        }

        void UnlockIRCGame(Bot bot, Game game)
        {
            SendIRCCommand(bot.Server, bot.Port, bot.Channel,
                string.Format("{0} {1} {2}", bot.Name, "unlock", game.Port.ToString()), bot);
        }

        [System.Obsolete("Use StartIRCGame(Bot, Map)")]
        void StartIRCGame(string server, string channel, string map)
        {
            SendIRCCommand(server, channel, "Minbot map " + map);
        }

        void StartIRCGame(Bot bot, Game game, Map map)
        {
            string command;

            if (game.Type == "Strict")
                command = bot.CmdMapStrict;
            else
                command = bot.CmdMapOpen;

            SendIRCCommand(bot.Server, bot.Port, bot.Channel, 
                string.Format("{0} {1} {2}", bot.Name, command, map.Name), bot);
        }

        private void SendIRCCommand(string server, string port, string ch, string message, object tag)
        {
            irc.Tag = tag;

            // UTF-8 test
            irc.Encoding = System.Text.Encoding.UTF8;

            // wait time between messages, we can set this lower on own irc servers
            irc.SendDelay = 200;

            // we use channel sync, means we can use irc.GetChannel() and so on
            irc.ActiveChannelSyncing = true;

            // here we connect the events of the API to our written methods
            // most have own event handler types, because they ship different data
            irc.OnError += new Meebey.SmartIrc4net.ErrorEventHandler(OnError);
            irc.OnRawMessage += new IrcEventHandler(OnRawMessage);

            string[] serverlist;
            // the server we want to connect to, could be also a simple string
            serverlist = new string[] { server };
            int _port = int.Parse(port);
            string channel = ch;
            try
            {
                if (irc.IsConnected)
                    irc.Disconnect();

                // here we try to connect to the server and exceptions get handled
                irc.Connect(serverlist, _port);
            }
            catch (ConnectionException e)
            {
                // something went wrong, the reason will be shown
                System.Console.WriteLine("couldn't connect! Reason: " + e.Message);
            }

            try
            {
                // here we logon and register our nickname and so on 
                irc.Login("Smart Tracker", "Smart Tracker Bot", 4, "SmartTracker", "");
                // join the channel
                irc.RfcJoin(channel);

                irc.SendMessage(SendType.Message, channel, message);

                //                irc.Disconnect();
                // here we tell the IRC API to go into a receive mode, all events
                // will be triggered by _this_ thread (main thread in this case)
                // Listen() blocks by default, you can also use ListenOnce() if you
                // need that does one IRC operation and then returns, so you need then 
                // an own loop 
                irc.Listen();

                // when Listen() returns our IRC session is over, to be sure we call
                // disconnect manually
                //                irc.Disconnect();
            }
            catch (ConnectionException)
            {
                // this exception is handled because Disconnect() can throw a not
                // connected exception
            }
            catch (Exception e)
            {
                // this should not happen by just in case we handle it nicely
                System.Console.WriteLine("Error occurred! Message: " + e.Message);
                System.Console.WriteLine("Exception: " + e.StackTrace);
            }
        }

        [System.Obsolete("Use SendIRCCommand(string server, string port, string ch, string message)")]
        private void SendIRCCommand(string server, string ch, string message)
        {
            SendIRCCommand(server, "6667", ch, message, null);
        }

        #endregion

        private void autoStartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            chkAutoStart.Checked = true;
        }
        
        private void frmSettings_Activated(object sender, EventArgs e)
        {
            lstGameList.Focus();
        }


        private void lblMap_Click(object sender, EventArgs e)
        {
            lblMap.SelectAll();
        }

        private void TrackAndRefresh()
        {
            this.Cursor = Cursors.WaitCursor;
            btnRefreshGameList.Enabled = false;

            Track(false);

            RefreshGameList();

            btnRefreshGameList.Enabled = true;
            this.Cursor = Cursors.Default;
        }

        //private void txtServer_TextChanged(object sender, EventArgs e)
        //{
        //    btnStartServer.Enabled = txtLocalMap.Text.Length > 0;
        //}

        private void radCustom_CheckedChanged(object sender, EventArgs e)
        {
            txtIRCBotName.Enabled = true;
            txtIRCChannel.Enabled = true;
            txtIRCMap.Enabled = true;
            txtIRCPort.Enabled = true;
            txtIRCServer.Enabled = true;
            txtIRCStrictOp.Enabled = true;
            txtIRCOpenOp.Enabled = true;
            chkCanKill.Enabled = true;
            chkCanLock.Enabled = true;

            cmbBotList.Enabled = false;
            cmbMapList.Enabled = false;

        }

        private void radStandard_CheckedChanged(object sender, EventArgs e)
        {
            txtIRCBotName.Enabled = false;
            txtIRCChannel.Enabled = false;
            txtIRCMap.Enabled = false;
            txtIRCPort.Enabled = false;
            txtIRCServer.Enabled = false;
            txtIRCStrictOp.Enabled = false;
            txtIRCOpenOp.Enabled = false;
            chkCanKill.Enabled = false;
            chkCanLock.Enabled = false;

            cmbBotList.Enabled = true;
            cmbMapList.Enabled = true;
        }

        private static string InputBox(string prompt, string title, string defaultValue)
        {
            InputBoxDialog ib = new InputBoxDialog();
            ib.FormPrompt = prompt;
            ib.FormCaption = title;
            ib.DefaultValue = defaultValue;
            ib.ShowDialog();
            string s = ib.InputResponse;
            ib.Close();
            return s;
        }

        private void lstGameList_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Control == true & e.KeyCode == Keys.I)
            {
                portList.Add(gameList[this.lstGameList.SelectedIndex].Port);

                e.Handled = true;
            }
            else if (e.Control == true & e.KeyCode == Keys.R)
            {
                portList.Remove(gameList[this.lstGameList.SelectedIndex].Port);
                
                e.Handled = true;
            }
        }

        private void btnBrowseServerExe_Click(object sender, EventArgs e)
        {
//            openWBDSFileDialog.Filter = "WinBoloDS (*.exe)|*.exe";
            openWBDSFileDialog.InitialDirectory = "C:\\";
            DialogResult result = openWBDSFileDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtLocalServer.Text = openWBDSFileDialog.FileName;
            }

        }

        private void chkLocalPassword_CheckedChanged(object sender, EventArgs e)
        {
            mtxtLocalPassword.Enabled = chkLocalPassword.Checked;
        }

        private void btnBrowseMap_Click(object sender, EventArgs e)
        {
            openWBDSFileDialog.Filter = "Bolo map (*.map)|*.map";
            openWBDSFileDialog.InitialDirectory = "C:\\";
            DialogResult result = openWBDSFileDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                txtLocalMap.Text = openWBDSFileDialog.FileName;
            }

        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            p.StandardInput.WriteLine("quit");
        }

    }
}
